﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Web.Mvc;
using Wisdom.Core;

namespace Wisdom.Web.Mvc
{
    /// <summary>
    /// Defines an static class which contains extension methods of <see cref="TypeMappingRegistry{Controller, IActionInvoker}"/>.
    /// </summary>
    public static class ActionInvokerMappingExtensions
    {
        /// <summary>
        /// Registers the specified instance.
        /// </summary>
        /// <typeparam name="TController">The type of the controller.</typeparam>
        /// <typeparam name="TActionInvoker">The type of the action invoker.</typeparam>
        /// <param name="instance">The instance.</param>
        /// <returns></returns>
        public static TypeMappingRegistry<Controller, IActionInvoker> Register<TController, TActionInvoker>(this TypeMappingRegistry<Controller, IActionInvoker> instance)
            where TController : Controller
            where TActionInvoker : IActionInvoker
        {
            Guard.IsNotNull(instance, "instance");

            instance.Register(typeof(TController), typeof(TActionInvoker));

            return instance;
        }

        /// <summary>
        /// Registers the specified instance.
        /// </summary>
        /// <typeparam name="TController1">The type of the controller1.</typeparam>
        /// <typeparam name="TController2">The type of the controller2.</typeparam>
        /// <typeparam name="TActionInvoker">The type of the action invoker.</typeparam>
        /// <param name="instance">The instance.</param>
        /// <returns></returns>
        public static TypeMappingRegistry<Controller, IActionInvoker> Register<TController1, TController2, TActionInvoker>(this TypeMappingRegistry<Controller, IActionInvoker> instance)
            where TController1 : Controller
            where TController2 : Controller
            where TActionInvoker : IActionInvoker
        {
            Guard.IsNotNull(instance, "instance");

            Type actionInvokerType = typeof(TActionInvoker);

            instance.Register(typeof(TController1), actionInvokerType);
            instance.Register(typeof(TController2), actionInvokerType);

            return instance;
        }

        /// <summary>
        /// Registers the specified instance.
        /// </summary>
        /// <typeparam name="TController1">The type of the controller1.</typeparam>
        /// <typeparam name="TController2">The type of the controller2.</typeparam>
        /// <typeparam name="TController3">The type of the controller3.</typeparam>
        /// <typeparam name="TActionInvoker">The type of the action invoker.</typeparam>
        /// <param name="instance">The instance.</param>
        /// <returns></returns>
        public static TypeMappingRegistry<Controller, IActionInvoker> Register<TController1, TController2, TController3, TActionInvoker>(this TypeMappingRegistry<Controller, IActionInvoker> instance)
            where TController1 : Controller
            where TController2 : Controller
            where TController3 : Controller
            where TActionInvoker : IActionInvoker
        {
            Guard.IsNotNull(instance, "instance");

            Type actionInvokerType = typeof(TActionInvoker);

            instance.Register(typeof(TController1), actionInvokerType);
            instance.Register(typeof(TController2), actionInvokerType);
            instance.Register(typeof(TController3), actionInvokerType);

            return instance;
        }

        /// <summary>
        /// Registers the specified instance.
        /// </summary>
        /// <typeparam name="TController1">The type of the controller1.</typeparam>
        /// <typeparam name="TController2">The type of the controller2.</typeparam>
        /// <typeparam name="TController3">The type of the controller3.</typeparam>
        /// <typeparam name="TController4">The type of the controller4.</typeparam>
        /// <typeparam name="TActionInvoker">The type of the action invoker.</typeparam>
        /// <param name="instance">The instance.</param>
        /// <returns></returns>
        public static TypeMappingRegistry<Controller, IActionInvoker> Register<TController1, TController2, TController3, TController4, TActionInvoker>(this TypeMappingRegistry<Controller, IActionInvoker> instance)
            where TController1 : Controller
            where TController2 : Controller
            where TController3 : Controller
            where TController4 : Controller
            where TActionInvoker : IActionInvoker
        {
            Guard.IsNotNull(instance, "instance");

            Type actionInvokerType = typeof(TActionInvoker);

            instance.Register(typeof(TController1), actionInvokerType);
            instance.Register(typeof(TController2), actionInvokerType);
            instance.Register(typeof(TController3), actionInvokerType);
            instance.Register(typeof(TController4), actionInvokerType);

            return instance;
        }

        /// <summary>
        /// Registers the specified instance.
        /// </summary>
        /// <typeparam name="TActionInvoker">The type of the action invoker.</typeparam>
        /// <param name="instance">The instance.</param>
        /// <param name="typeCatalog">The type catalog.</param>
        /// <returns></returns>
        public static TypeMappingRegistry<Controller, IActionInvoker> Register<TActionInvoker>(this TypeMappingRegistry<Controller, IActionInvoker> instance, TypeCatalog typeCatalog)
            where TActionInvoker : IActionInvoker
        {
            Guard.IsNotNull(instance, "instance");
            Guard.IsNotNull(typeCatalog, "typeCatalog");
            
            typeCatalog.EnsureTypes(KnownTypes.ControllerType);

            Type actionInvokerType = typeof(TActionInvoker);

            foreach (Type controllerType in typeCatalog)
            {
                instance.Register(controllerType, actionInvokerType);
            }

            return instance;
        }
    }
}